﻿using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

namespace UnityExtensions
{
	public delegate UObjectPool<T> PoolCreateD<T>(Transform parent, T baseObj) where T : Object;
	public class UObjectPoolManager<T> where T:Object
	{
		private Transform mParent;//
		private readonly Dictionary<string,UObjectPool<T>> mPools = new Dictionary<string, UObjectPool<T>>();//
		private readonly Dictionary<int,string> mInstanceId2PoolName = new Dictionary<int, string>(50);
		public event PoolCreateD<T> PoolCreateE; //

		public UObjectPoolManager()
		{
			
		}
		public UObjectPoolManager(Transform parent)
		{
			SetParent(parent);
		}

		public UObjectPoolManager(PoolCreateD<T> poolCreate)
		{
			PoolCreateE = poolCreate;
		}

		public void SetParent(Transform v)
		{
			mParent = v;
		}

		public UObjectPool<T> AddPool(string name,T baseObj)
		{
			UObjectPool<T> pool;
			if (mPools.TryGetValue(name, out pool))
			{
				return pool;
			}

			if (PoolCreateE != null) pool = PoolCreateE(mParent, baseObj);
			mPools[name] = pool;
			return pool;
		}

		public T GetOrAddPool(string name, T baseObj)
		{
			UObjectPool<T> pool;
			if (mPools.TryGetValue(name, out pool) == false)
			{
				pool = AddPool(name, baseObj);
			}

			var item = pool.Get();
			mInstanceId2PoolName[item.GetInstanceID()] = name;
			return item;
		}
		public T Get(string name)
		{
			UObjectPool<T> pool;
			if (mPools.TryGetValue(name, out pool))
			{
				var transform = pool.Get();
				mInstanceId2PoolName[transform.GetInstanceID()] = name;
				return transform;
			}
			else
			{
				Debug.LogErrorFormat("not exit pool:{0}",name);
				return null;
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="item"></param>
		public void Recycle(T item)
		{
			if (item == null) throw new ArgumentNullException("item");
			var instanceId = item.GetInstanceID();
			string pooName;
			if (mInstanceId2PoolName.TryGetValue(instanceId,out pooName))
			{
				var pool = mPools[pooName];
				pool.Recycle(item);
				mInstanceId2PoolName.Remove(instanceId);
			}
			else
			{
				Debug.LogErrorFormat("not in pool item:{0}",item.name);
			}
		}
		/// <summary>
		/// clear target name pool
		/// </summary>
		/// <param name="name"></param>
		public void Clear(string name)
		{
			UObjectPool<T> pool;
			if (mPools.TryGetValue(name, out pool))
			{
				pool.Clear(it =>
				{
					mInstanceId2PoolName.Remove(it.GetInstanceID());
					Object.Destroy(it);
				});
			}
		}
		/// <summary>
		/// Clear All Pool
		/// </summary>
		public void Clear()
		{
			foreach (var it in mPools)
			{
				var pool = it.Value;
				pool.Clear(UnityEngine.Object.Destroy);
			}
			mInstanceId2PoolName.Clear();
			mPools.Clear();
		}

	}
}